package com.piesat.quake.business.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.piesat.common.exception.BadRequestException;
import com.piesat.common.exception.EntityExistException;
import com.piesat.common.exception.EntityNotFoundException;
import com.piesat.common.utils.SecurityUtils;
import com.piesat.common.utils.StringUtils;
import com.piesat.quake.business.system.mapper.SysRoleMapper;
import com.piesat.quake.business.system.mapper.SysUserMapper;
import com.piesat.quake.business.system.model.SysRole;
import com.piesat.quake.business.system.model.SysUser;
import com.piesat.quake.business.system.model.SysUserDTO;
import com.piesat.quake.business.system.model.dto.UserDTO;
import com.piesat.quake.business.system.service.SysUserService;
import com.piesat.security.service.dto.UserDto;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.Objects;
import java.util.Optional;

import lombok.RequiredArgsConstructor;

/**
 * <p>
 * 系统用户 服务实现类
 * </p>
 *
 * @author ${author}
 * @since 2022-04-22
 */
@Service
@RequiredArgsConstructor
@CacheConfig(cacheNames = "user")
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {

    private final SysUserMapper userMapper;
    private final SysRoleMapper roleMapper;
    private final PasswordEncoder passwordEncoder;
    @Value("${path.doc-path}")
    private String docPath;

    @Override
    public UserDto findByName(String username) {
        QueryWrapper<SysUser> wrapper = new QueryWrapper<>();
        wrapper.eq("username", username);
        SysUser user = Optional.ofNullable(userMapper.selectOne(wrapper)).orElseThrow(() -> new EntityNotFoundException(SysUser.class, "name", username));
        SysRole role = null;
        if (user.getRoleId() != null) {
            role = roleMapper.selectById(user.getRoleId());
        }
//        UserDto userDto = new UserDto(user.getUserId(), user.getUsername(), user.getNickName(), user.getPassword(), user.getEmail(), user.getPhone(), user.getGender(), user.getAvatarName(), user.getAvatarPath(), user.getIsAdmin(), user.getEnabled(), user.getPwdResetTime(), user.getRoleId(), role == null ? 0L : 0L, user.getAuditState());
        return SysUserDTO.convertFrom(user,role);
    }

    @Override
    public Page<SysUser> selectPage(UserDTO dto) {

        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(SysUser::getNickName, dto.getBlurry());
        if (Objects.nonNull(dto.getEnabled())) {
            wrapper.eq(SysUser::getEnabled, dto.getEnabled());
        }
        if (Objects.nonNull(dto.getCreateTime()) && dto.getCreateTime().size() == 2) {
            wrapper.between(SysUser::getCreateTime, dto.getCreateTime().get(0), dto.getCreateTime().get(1));
        }
        return this.page(new Page<>(dto.getPage(), dto.getSize()), wrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void create(SysUser user) {
        if (StringUtils.isNotBlank(user.getRoleId()) && (user.getIsAdmin() || user.getRoleId().equals("1"))) {
            //系统管理员用户只有一个，不能创建
            throw new BadRequestException("系统管理员只有一个，不能创建系统管理员");
        }
        int count = this.count(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUsername, user.getUsername()));
        if (count > 0) {
            throw new EntityExistException(SysUser.class, "username", user.getUsername());
        }
        this.save(user);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(SysUser user) {
        if (user.getIsAdmin() || user.getRoleId().equals("1")) {
            throw new BadRequestException("不能修改系统管理员账户");
        }
        Optional.ofNullable(this.getById(user.getUserId())).orElseThrow(() -> new EntityNotFoundException(SysUser.class, "id", user.getUserId()));
        this.updateById(user);
    }

    @Override
    public void delete(String id) {
        if (id.equals("1")) {
            throw new BadRequestException("不能删除超级管理员账号");
        }
        this.removeById(id);
    }

    @Override
    public String getRoleIdByUserName(String username) {
        return this.getOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUsername, username)).getRoleId();
    }

    @Override
    public void updatePassword(String oldPassword, String newPassword) throws Exception {
        //获取当前用户
        String username = SecurityUtils.getCurrentUsername();
        //根据用户名，查询对应用户
        SysUser sysUser = Optional.ofNullable(this.getOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUsername, username)))
                .orElseThrow(() -> new Exception("该用户不存在！！！"));
        if (!passwordEncoder.matches(oldPassword, sysUser.getPassword())) {
            throw new BadRequestException("旧密码与原始密码不相等");
        }
        sysUser.setPassword(passwordEncoder.encode(newPassword));
        this.updateById(sysUser);
    }

    @Override
    public void resetPassword(String userId) throws Exception {
        SysUser sysUser = Optional.ofNullable(this.getById(userId)).orElseThrow(() -> new Exception("该用户不存在！！！"));
        sysUser.setPassword(passwordEncoder.encode("123456"));
        this.updateById(sysUser);
    }

    @Override
    public boolean uploadDoc(MultipartFile multipartFile) {
        try {
            File file = new File(docPath);
            file.mkdirs();
            multipartFile.transferTo(new File(file,"help.doc"));
            return true;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }
}
